﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.IO.IsolatedStorage;
using System.Diagnostics;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.ComponentModel;
using System.Text;
using Hardcodet.Silverlight.Util;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using System.Collections.Specialized;
using System.Threading;
using System.Data.Linq;
using System.Windows.Data;
using Windows.UI.ViewManagement;
using Windows.ApplicationModel.Store;
using Microsoft.Phone.Shell;

namespace depl
{



    public class DictEntry : IComparable<DictEntry>
    {
        public int Id;
        public string Name;
        public string NormalizedName;

        public override string ToString()
        {
            return Name;
        }

        public int CompareTo(DictEntry compareEntry)
        {
            return Name.CompareTo(compareEntry.Name);
        }

    }


    public class SearchResults: ObservableCollection<Entry>
    {
    }

    public partial class PivotPage1 : PhoneApplicationPage
    {

        public const int MAX_INPUT_LENGTH = 100;
        public const int MIN_PREFIX_LENGTH = 3;
        public const int MIN_POPULATE_DELAY = 0;
        public const int MAX_AUTOCOMPLETE_RESULTS = 6;
        public const int MAX_SEACH_RESULTS = 30;
        public const int MAX_LEVENSHTEIN_DISTANCE = 2;
        public const int MAX_HISTORY_ENTRIES = 15;
        public const int MAX_FAVOURITES_ENTRIES = 100;
        public const int MAX_LEADING_LETTERS = 50;
        public const int QUERY_ID_UNDEFINED = -1;
        
        public const string COMPLETED_FILENAME = "completed";
        public const string NOADS_FILENAME = "noads";
        public const string NOADS_PRODUCT_ID = "RemoveAds";

        private static ProgressDialog m_downloadingDialog = new ProgressDialog(AppResources.DownloadingPopupText);
        private static ProgressDialog m_extractingDialog = new ProgressDialog(AppResources.UnpackingPopupText);

        List<string> Names = new List<string>();
        List<DictEntry>[] Suggestions = new List<DictEntry>[255];
        Dictionary<string, Entry> Entries = new Dictionary<string, Entry>();//Dictionary to index entries by its name(needed for related entries)
       
        //List<IdToKeyword> IdToKeywords = new List<IdToKeyword>();
        List<DictEntry> CurrentPopulateResults = null;
        List<Entry> ProbableResults = new List<Entry>();
        List<Entry> ExactResults = new List<Entry>();

        //EntryDataContext entryDataContext = new EntryDataContext();
        //public static EntryStorageContext entryStorageContext = new EntryStorageContext();

        SearchResults FinalResults = new SearchResults();
        private Mutex _entryLoadedMutex = new Mutex();

        bool _entriesLoaded = false;
        bool _isAdFreeVersion = false;
        public string receipt;

        DictEntry CurrentlySelectedEntry = null;
        SearchCache Cache = new SearchCache();
        int pageSelected = 0;
        static int results = 0;
        int EntryCount = 0;
        int prevPopulatedLength = 0;
        int prevInputLength = 0;
        DictEntry CurrentQuery = new DictEntry {Id=-1, Name="", NormalizedName=""};
        bool searchInProgres = false;

        bool isUpdatingDatabase = false;
        bool dropDownComposing = false;
        bool _adReady = false;
        bool _adShouldShow = false;
        //static public EntryStorage Favourites = new EntryStorage("favourites.dat", MAX_FAVOURITES_ENTRIES);
        //RelatedEntryIdx.static public EntryStorage History = new EntryStorage("history.dat", MAX_HISTORY_ENTRIES);
       // private bool isHistorySearch = false;//variable used for controlling adding data 


        static public bool ItemFilter(string search, object value)
        {
            if (results >= MAX_AUTOCOMPLETE_RESULTS)
                return false;

            bool result = false;
            DictEntry query = value as DictEntry;
            result = query.NormalizedName.StartsWith(StringUtil.RemoveDiacritics(search));

            if (result)
            {
                results++;
                result = true;
            }
            return result;
        }

        private void AutoCompleteBox_Populating(object sender, PopulatingEventArgs e)
        {
            if (queryInput.isShowingHistory)
                return;
            e.Cancel = true;
            List<DictEntry> CachedDataSource = null;

            int populatedLength = queryInput.Input.Text.Length;
            if (searchInProgres)
            {
                Debug.WriteLine("search in progress");
                return;
            }
            if (dropDownComposing)
            {
                Debug.WriteLine("drop down composing in progress");
                return;
            }
            if (populatedLength < MIN_PREFIX_LENGTH)
            {
                Debug.WriteLine("length is less than minimum");
                return;
            }
            dropDownComposing = true;
            if (populatedLength < prevPopulatedLength)//use cached reults
            {
                CachedDataSource = Cache.Load(populatedLength);
            }
            else
            {
                if (populatedLength > queryInput.Input.MinimumPrefixLength)
                {
                    if (CurrentPopulateResults != null)
                    {
                        Debug.WriteLine("storing prevLen: "+prevPopulatedLength+" currentLength: "+populatedLength);
                        Cache.Store(prevPopulatedLength, CurrentPopulateResults);
                    }
                    CurrentPopulateResults = null;
                }

            }
            
            if (CachedDataSource != null)
            {
                Debug.WriteLine("populating cached results");
                queryInput.Input.ItemsSource = CachedDataSource;
            }
            else
            {

                Debug.WriteLine("populating whole database");
                char idx = StringUtil.RemoveDiacritics(char.ToLower(queryInput.Input.Text[0]));
                if (Suggestions[idx] != null)
                {
                    queryInput.Input.ItemsSource = Suggestions[idx];
                }
                else
                {
                    Debug.WriteLine("invalid leading character");
                    queryInput.Input.ItemsSource = null;
                }
         
                
            }
            results = 0;
            queryInput.Input.PopulateComplete();


        }

        private void AutoCompleteBox_Populated(object sender, PopulatedEventArgs e)
        {
            if (queryInput.isShowingHistory)
                return;
            IEnumerable<DictEntry> strings = e.Data.Cast<DictEntry>();
            int populatedLength = queryInput.Input.Text.Length;
            Debug.WriteLine("storing actual results to temporary value");
            CurrentPopulateResults = new List<DictEntry>(strings);
            if (strings.ToList().Count == 0)
            {
                Debug.WriteLine("no results");
                dropDownComposing = false;
            }
            Debug.WriteLine("populated: " + strings.ToList().Count);
            prevPopulatedLength = populatedLength;
        }

        private void AutoCompleteBox_GotFocus(object sender, RoutedEventArgs e)
        {
           
                //TranslateTransform myTranslate = new TranslateTransform();
                //myTranslate.X = 0;
                //myTranslate.Y = -LayoutRoot.ActualHeight + AdMediator_depl.Height +queryInput.Height-7;
                //AdWindow.RenderTransform = myTranslate;
            
        }

        private void AutoCompleteBox_LostFocus(object sender, RoutedEventArgs e)
        {
            //TranslateTransform myTranslate = new TranslateTransform();
            //myTranslate.X = 0;
            //myTranslate.Y = 0;
            //AdWindow.RenderTransform = myTranslate;
            

            HistoryItem historyItem = queryInput.HistorySelectedItem;
            if (historyItem != null)
            {
                Debug.WriteLine("historyitem: " + historyItem.Name);
                DictEntry historyQuery = new DictEntry
                {
                    Name = historyItem.Name,
                    NormalizedName = StringUtil.RemoveDiacritics(historyItem.Name),
                    Id = historyItem.Id
                };

                PerformSearchAsync(historyQuery);//search already saves to history

                queryInput.HistorySelectedItem = null;
                return;
            }

            DictEntry SelectedEntry = queryInput.Input.SelectedItem as DictEntry;

            if ((SelectedEntry != null) && (CurrentlySelectedEntry != SelectedEntry) && (!isUpdatingDatabase) && (!queryInput.isShowingHistory) && (CurrentQuery.Name != queryInput.Input.Text))
            {
                //History.Save(SelectedEntry);
                //ResultPanel.Children.Clear();
                //HtmlBox resultBox = new HtmlBox();
                //resultBox.Title = SelectedEntry.name;
                //resultBox.HtmlText = SelectedEntry.content;
                //ResultPanel.Children.Add(resultBox);
                FinalResults.Clear();
                //Entry reversedEntry = SelectedEntry as Entry;
                PerformSearchAsync(SelectedEntry);

                //if (SelectedEntry.Content != "")
                
                   // FinalResults.Add(SelectedEntry);
                

                //foreach(string entryName in reversedEntry.RelatedEntryNames)
               // {
                    //FinalResults.Add(Entries[StringUtil.RemoveDiacritics(entryName[0])][entryName]);
               // }

                //SearchsListSelector.Focus();
                //SearchHint.Visibility = Visibility.Collapsed;
                Debug.WriteLine("selectedItem: " + SelectedEntry.Id + ". " + SelectedEntry.Name);
                CurrentlySelectedEntry = SelectedEntry;
                Cache.Store(prevPopulatedLength, CurrentPopulateResults);
                prevPopulatedLength = queryInput.Input.Text.Length;
                CurrentQuery = SelectedEntry;
                EntryStorage.Instance.StoreHistory(CurrentQuery);
            }
        }

        private void AutoCompleteBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Debug.WriteLine("pressed enter");
                if (StringUtil.RemoveBlanks(queryInput.Input.Text) != "")
                {
                    //isHistorySearch = false;
                    DictEntry CustomQuery = new DictEntry() {
                        Id = QUERY_ID_UNDEFINED,
                        Name = queryInput.Input.Text,
                        NormalizedName = StringUtil.RemoveDiacritics(queryInput.Input.Text)
                    };
                    PerformSearchAsync(CustomQuery);
                    EntryStorage.Instance.StoreHistory(CustomQuery);
                }
                //ScrollViewer.Focus();
            }
        }

        private void AutoCompleteBox_TextChanged(object sender, RoutedEventArgs e)
        {
            
            if (queryInput.isShowingHistory)
            {
                Debug.WriteLine("text changed to history");
                CurrentPopulateResults = null;
                Cache.Clear();
                return;
            }
            Debug.WriteLine("currentText: " + queryInput.Input.Text);
            int length = queryInput.Input.Text.Length;
            if (length < prevInputLength)
            {
                for (int i = length + 1; i <= prevInputLength; i++)
                {
                    Debug.WriteLine("clearing cache " + i);
                    Cache.Clear(i);
                }
            }
            prevInputLength = queryInput.Input.Text.Length;
        }

        private void AutoCompleteBox_DropDownOpened(object sender, RoutedPropertyChangedEventArgs<bool> e)
        {
            dropDownComposing = false;
        }
        public PivotPage1()
        {
            bool needUpdate = false;
            bool isRootfsCompatibile = false;
            InitializeComponent();
            

            this.queryInput.Input.MinimumPrefixLength = MIN_PREFIX_LENGTH;
            this.queryInput.Input.MinimumPopulateDelay = MIN_POPULATE_DELAY;
            this.queryInput.Input.Populating += AutoCompleteBox_Populating;
            this.queryInput.Input.Populated += AutoCompleteBox_Populated;
            this.queryInput.Input.TextChanged += AutoCompleteBox_TextChanged;
            this.queryInput.Input.DropDownOpened += AutoCompleteBox_DropDownOpened;
            this.queryInput.Input.ItemFilter = ItemFilter;
            this.queryInput.LostFocus += AutoCompleteBox_LostFocus;
            this.queryInput.GotFocus += AutoCompleteBox_GotFocus;
            this.queryInput.KeyUp += AutoCompleteBox_KeyUp;
            //this.ScrollViewer.MouseMove += ScrollViewer_MouseMove;

            //History.Load();//initialize count
            //Favourites.Load();

            var inputPane = InputPane.GetForCurrentView();
            inputPane.Showing += this.InputPaneShowing;
            inputPane.Hiding += this.InputPaneHiding;

            SearchsListSelector.ItemsSource = FinalResults;

            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (store.FileExists(COMPLETED_FILENAME))
                {
                    using (TextReader reader = new StreamReader(new IsolatedStorageFileStream(COMPLETED_FILENAME, System.IO.FileMode.Open, store), new CustomEncoding(), true))
                    {
                        string version = reader.ReadLine();
                        if (version != null)
                        {
                            isRootfsCompatibile = (version == AppResources.RootfsVersionText);
                        }

                    }
                }

                if (!isRootfsCompatibile)
                {
                    Debug.WriteLine("The exisiting rootfs version is incompatibile to current version: " + AppResources.RootfsVersionText);
                    ClearRoot();
                }
                needUpdate = !store.FileExists(COMPLETED_FILENAME);
                if (!needUpdate)
                {
                    ParseDatabaseSync(null);
                    //this.queryInput.Input.ItemsSource = Entries;
                }

                FavouritesHint.DataContext = EntryStorage.Instance;
                EntryStorage.Instance.GetFavs();
                EntryStorage.Instance.GetHistory();
                Loaded += OnPageLoaded;

            }
        }

        private void OnPageLoaded(object sender, RoutedEventArgs e)
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (store.FileExists(COMPLETED_FILENAME))
                {
                    if (!_entriesLoaded)
                    {
                        LoadEntriesAsync();
                        CheckIfAddFree();
                        ShowAd();
                    }
                }
                else
                {
                    UpdateDatabaseAsync();
                }
            }
            Loaded -= OnPageLoaded;
        }

        private void InputPaneShowing(InputPane sender, InputPaneVisibilityEventArgs args)
        {
            Debug.WriteLine("InputPaneShowing");
        }

        private void InputPaneHiding(InputPane sender, InputPaneVisibilityEventArgs args)
        {
            Debug.WriteLine("InputPaneHiding");
        }

        private void ScrollViewer_MouseMove(object sender, MouseEventArgs e)
        {
            
           // ScrollViewer.Focus();
        }





        void UpdateDatabaseAsync()
        {
            if (MessageBox.Show(AppResources.UpdatingText, AppResources.UpdatingHeaderText, MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                isUpdatingDatabase = true;
                this.Focus();
                m_downloadingDialog.progressType = ProgressDialog.ProgressTypes.DeterminateMiddle;
                m_downloadingDialog.Show();
                ApplicationBar.IsVisible = false;
                DownloadAsync("http://www.depl.pl/wyrazy.zip");
            };
        }

        private static void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
        {
            m_downloadingDialog.progressBar.Value = e.ProgressPercentage;
        }

        private void DownloadAsync(string uri)
        {
            string fileName = System.IO.Path.GetFileName(uri);
            IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
            if (store.FileExists(COMPLETED_FILENAME))
            {
                store.DeleteFile(COMPLETED_FILENAME);
                store.DeleteFile(NOADS_FILENAME);
                store.DeleteFile(fileName);
                store.DeleteFile("d.dat");
                store.DeleteFile("e.dat");
                EntryStorage.Instance.ClearHistory();
            }

            try
            {
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
                wc.OpenReadCompleted += ((s, args) =>
                {
                    if (args.Error != null)
                    {
                        Debug.WriteLine("openstream: " + args.Error);
                        m_downloadingDialog.Hide();
                        ApplicationBar.IsVisible = true;
                        MessageBox.Show(AppResources.ConnectionFailureText, AppResources.ConnectionFailureHeaderText, MessageBoxButton.OK);
                    }
                    else
                    {
                        using (var fs = new IsolatedStorageFileStream(fileName, FileMode.Create, store))
                        {
                            byte[] bytesInStream = new byte[args.Result.Length];
                            args.Result.Read(bytesInStream, 0, (int)bytesInStream.Length);
                            fs.Write(bytesInStream, 0, bytesInStream.Length);
                            fs.Flush();
                            m_downloadingDialog.Hide();
                            UnzipAsync();
                        }
                        Debug.WriteLine("Download " + uri + " has completed");
                    }

                });
                wc.OpenReadAsync(new System.Uri(uri, System.UriKind.RelativeOrAbsolute));
            }
            catch (Exception ex)
            {
                MessageBox.Show(AppResources.ConnectionFailureText, AppResources.ConnectionFailureHeaderText, MessageBoxButton.OK);
            }
        }

        private void UnzipThread_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            Unzip("wyrazy.zip");
        }

        private void UnzpiThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.WriteLine("UnzpiThread_RunWorkerCompleted");
            ParseDatabaseAsync();
        }

        private void UnzipAsync()
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = false;
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(UnzipThread_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(UnzpiThread_RunWorkerCompleted);
            m_extractingDialog.progressType = ProgressDialog.ProgressTypes.DeterminateMiddle;
            m_extractingDialog.Show();
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }

        private void Unzip(string fileName)
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                ZipEntry entry;
                int size;
                byte[] data = new byte[2048];

                using (ZipInputStream zip = new ZipInputStream(store.OpenFile(fileName, FileMode.Open)))
                {
                    // retrieve each file/folder
                    while ((entry = zip.GetNextEntry()) != null)
                    {
                        if (!entry.IsFile)
                            continue;

                        // if file name is music/rock/new.mp3, we need only new.mp3
                        // also you must make sure file name doesn't have unsupported chars like /,\,etc.
                        int index = entry.Name.LastIndexOf('/');

                        string name = entry.Name.Substring(index + 1);

                        // create file in isolated storage
                        using (var writer = store.OpenFile(name, FileMode.Create))
                        {
                            while (true)
                            {
                                size = zip.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    writer.Write(data, 0, size);

                                }
                                else
                                    break;
                            }
                        }
                    }
                }
            }

        }

        

        private void ParseThread_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            ParseDatabaseSync(worker);
        }

        private static void ParseProgressCallback(object sender, ProgressChangedEventArgs e)
        {
            m_extractingDialog.progressBar.Value = e.ProgressPercentage;
        }

        private void ParseThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.WriteLine("ParseThread_RunWorkerCompleted");

            m_extractingDialog.Hide();
            if (isUpdatingDatabase)
            {
                isUpdatingDatabase = false;
                MessageBox.Show(AppResources.UpdateDoneText + EntryCount, AppResources.UpdateDoneHeaderText, MessageBoxButton.OK);
            }

            ApplicationBar.IsVisible = true;
            //this.queryInput.Input.ItemsSource = Entries;
        }

        private void ParseDatabaseAsync()
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = false;
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(ParseThread_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ParseThread_RunWorkerCompleted);
            bw.ProgressChanged += new ProgressChangedEventHandler(ParseProgressCallback);
            ApplicationBar.IsVisible = false;
            m_extractingDialog.progressType = ProgressDialog.ProgressTypes.DeterminateMiddle;
            m_extractingDialog.Show();
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }



        private void ParseDatabaseSync(BackgroundWorker worker)
        {
            Dictionary<string, Entry> DictEntries = new Dictionary<string, Entry>();//temporary list to store all dict entries
            HashSet<string> tmpEntries = new HashSet<string>();
            Dictionary<string, Entry> ReversedDictEntries = new Dictionary<string, Entry>();//temporary list to store all reversed dict entries and provide fast lookup
            int entryNumber = 0;
            int percentComplete = 0;
            int prevPercentComplete = 0;
            EntryCount = 0;
            //IdToKeywords.Clear();
            Entries.Clear();
            Names.Clear();
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                bool reverseDatabaseExists = store.FileExists(COMPLETED_FILENAME);
                char prevLeadingLetter = '.';

                if (!reverseDatabaseExists)
                {
                    using (TextReader reader1 = new StreamReader(new IsolatedStorageFileStream("a.dat", System.IO.FileMode.Open, store), new CustomEncoding(), true))
                    {
                        string line;
                        while ((line = reader1.ReadLine()) != null)
                        {
                            EntryCount++;
                        }
                        Debug.WriteLine("LineCount: "+EntryCount);
                    }
                    using (TextReader reader1 = new StreamReader(new IsolatedStorageFileStream("a.dat", System.IO.FileMode.Open, store), new CustomEncoding(), true))
                    {
                        using (TextReader reader2 = new StreamReader(new IsolatedStorageFileStream("b.dat", System.IO.FileMode.Open, store), new CustomEncoding(), true))
                        {

                         

                            while (true)
                            {
                                if (worker != null)
                                {
                                    percentComplete = (int)((float)entryNumber / (float)EntryCount * 70);
                                    if (percentComplete != prevPercentComplete)
                                    {
                                        worker.ReportProgress(percentComplete);
                                        Debug.WriteLine("percent complete: " + percentComplete);
                                        prevPercentComplete = percentComplete;
                                    }
                                }

                                string entryContent = reader1.ReadLine();
                                string entryName = reader2.ReadLine();
                                if (entryName == null)
                                    break;
                                string normalizedName = StringUtil.RemoveDiacritics(entryName);
                                //string normalizedContent = StringUtil.RemoveDiacritics(entryContent);
                                string keywords;
                                List<string> translations;
                                StringUtil.ExtractTranslation(entryContent, out keywords, out translations);
                                Entry newEntry = new Entry()
                                {
                                    Name = entryName,
                                    NormalizedName = normalizedName,
                                    Content = entryContent,
                                    NormalizedContent = keywords,
                                    RelatedEntryNames = new List<string>()
                                };

                                  entryNumber++;
                                //Debug.WriteLine(entryName+" :"+keywords);
                                try
                                {
                                    DictEntries.Add(newEntry.Name, newEntry);
                                }
                                catch(ArgumentException ex)
                                {
                                    Debug.WriteLine("entry already exists (adding normal entry): " + newEntry.Name);
                                    DictEntries[newEntry.Name].Content = newEntry.Content;
                                    DictEntries[newEntry.Name].NormalizedContent = newEntry.NormalizedContent;
                                }
                               
                                
                                foreach (string translation in translations)
                                {
                                    Entry reversedEntry = null;
                                    string translationSplit = translation.Split(' ')[0];

                                    ReversedDictEntries.TryGetValue(translationSplit, out reversedEntry);//find out if the translation has not already been done
                                    if (translationSplit == entryName.ToLower())
                                    {
                                       // Debug.WriteLine("Ignoring reversed translation for entry: "+translationSplit);//translation louds exactly the same as the entry, ignore
                                        continue;
                                    }
                                    
                                    if (reversedEntry == null)//reversed entry does not exists so create it
                                    {
                                        string normalizedTranslationSplit = StringUtil.RemoveDiacritics(translationSplit);

                                        reversedEntry = new Entry()
                                        {
                                            Name = translationSplit,
                                            NormalizedName = normalizedTranslationSplit,
                                            Content = String.Empty,
                                            NormalizedContent = String.Empty,
                                            RelatedEntryNames = new List<string>()
                                        };

                                        try
                                        {
                                            DictEntries.Add(reversedEntry.Name, reversedEntry);
                                            ReversedDictEntries.Add(reversedEntry.Name, reversedEntry);
                                        }
                                        catch(ArgumentException ex)
                                        {
                                            Debug.WriteLine("entry already exists (adding reversed entry): " + reversedEntry.Name);
                                            DictEntries[reversedEntry.Name].RelatedEntryNames.Add(entryName); 
                                        }
                                    }
                                    if (!reversedEntry.RelatedEntryNames.Contains(newEntry.Name))
                                    {
                                         //Debug.WriteLine("Expanding entry " + reversedEntry.Name + ": " + newEntry.Name);
                                         reversedEntry.RelatedEntryNames.Add(newEntry.Name);
                                    }
                                }

                            }
                            entryNumber = 0;
                            List<Entry> SortedEntries = DictEntries.Values.ToList();
                            SortedEntries.Sort();

                            foreach (Entry entry in SortedEntries)
                                {
                                    if (worker != null)
                                    {
                                        percentComplete = 70 + (int)((float)entryNumber / (float)DictEntries.Count * 20);
                                        if (percentComplete != prevPercentComplete)
                                        {
                                            worker.ReportProgress(percentComplete);
                                            Debug.WriteLine("percent complete: " + percentComplete);
                                            prevPercentComplete = percentComplete;
                                        }
                                    }

                                    char leadingLetter = entry.NormalizedName[0];
                                    if (leadingLetter < 'a')
                                        continue;



                                    if (prevLeadingLetter != leadingLetter)
                                    {
                                        //leadingLetters.Add(leadingLetter);
                                        Suggestions[leadingLetter] = new List<DictEntry>();
                                        prevLeadingLetter = leadingLetter;
                                        
                                    }

                                    DictEntry newSuggestion = new DictEntry()
                                    {
                                        Id = entryNumber,
                                        Name = entry.Name,
                                        NormalizedName = entry.NormalizedName
                                    };


                                    try
                                    {
                                        Entries.Add(entry.Name, entry);
                                        Suggestions[leadingLetter].Add(newSuggestion);
                                    }
                                    catch (ArgumentException arg)
                                    {
                                        Debug.WriteLine("ArgumentException when adding " + entry.Name + ": " + arg.Message);
                                    }

                                    
                                    

                                    entryNumber++;
                                }
 
                            using (TextWriter writer = new StreamWriter(new IsolatedStorageFileStream("d.dat", System.IO.FileMode.OpenOrCreate, store), new CustomEncoding()))
                            {
                                for (int i = 0; i < 255; i++)
                                {
                                    if (Suggestions[i] != null)
                                    {
                                        writer.WriteLine(Convert.ToChar(i));
                                        writer.WriteLine(Suggestions[i].Count);
                                        foreach (DictEntry suggestion in Suggestions[i])
                                        {
                                            writer.WriteLine(suggestion.Name);
                                            writer.WriteLine(suggestion.NormalizedName);
                                        }

                                    }
                                }
                            }
                            worker.ReportProgress(95);

                            
                            using (TextWriter writer = new StreamWriter(new IsolatedStorageFileStream("e.dat", System.IO.FileMode.OpenOrCreate, store), new CustomEncoding()))
                            {
                                foreach (Entry entry in Entries.Values)
                                {
                                    writer.WriteLine(entry.Content);
                                    writer.WriteLine(entry.NormalizedContent);
                                    writer.WriteLine(entry.RelatedEntryNames.Count);
                                    foreach (string relatedEntryName in entry.RelatedEntryNames)
                                    {
                                        writer.WriteLine(relatedEntryName);
                                    }
                                    
                                }
                            }
                            worker.ReportProgress(100);
                            IsolatedStorageFileStream fs = store.CreateFile(COMPLETED_FILENAME);
                            using (TextWriter writer = new StreamWriter(fs))
                            {
                                writer.WriteLine(AppResources.RootfsVersionText);
                            }
                            fs.Close();
                        }
                    }
                    GetLicenseAsync();

                    _entriesLoaded = true;
                }
                else
                {
                    using (TextReader reader = new StreamReader(new IsolatedStorageFileStream("d.dat", System.IO.FileMode.Open, store), new CustomEncoding(), true))
                    {
                        int cnt = 0;
                        while (true)
                        {
                            string letterString = reader.ReadLine();
                            if (letterString == null)
                                break;
                            char leadingLetter = Convert.ToChar(letterString[0]);
                            if (Suggestions[leadingLetter] == null)
                            {
                                Suggestions[leadingLetter] = new List<DictEntry>();
                            }
                            string leadingLetterEntryCountString = reader.ReadLine();
                            int leadingLetterEntryCount = Convert.ToInt32(leadingLetterEntryCountString);
                            for (int i = 0; i < leadingLetterEntryCount; i++)
                            {
                                string name = reader.ReadLine();
                                string normalizedName = reader.ReadLine();
                                DictEntry suggestion = new DictEntry()
                                {
                                    Id = cnt,
                                    Name = name,
                                    NormalizedName = normalizedName
                                };
                                
                                Suggestions[leadingLetter].Add(suggestion);
                                Names.Add(name);
                                cnt++;
                            }
                        }
                    }
                }
            }
        }



        async private void GetLicenseAsync()
        {
            var listing = await CurrentApp.LoadListingInformationAsync();
            var obj = listing.ProductListings.FirstOrDefault(
                        p => p.Value.ProductId == NOADS_PRODUCT_ID);

            if (CurrentApp.LicenseInformation.ProductLicenses[obj.Value.ProductId].IsActive)
            { 
                Debug.WriteLine("License detected using ad free version");
                _isAdFreeVersion = true;

                Dispatcher.BeginInvoke(() =>
                {
                    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        store.CreateFile(NOADS_FILENAME).Close();
                    }
                    if ((ApplicationBar as ApplicationBar).MenuItems.Count == 3)
                    {
                        (ApplicationBar as ApplicationBar).MenuItems.RemoveAt(1);//delete remove ads button if it exists
                    }
                    //MessageBox.Show("Using ad free version");
                });
                Debug.WriteLine("GetLicenseAsync - releasing mutex");
            }
        }

        private void LoadEntriesSync()
        {
            if (_entryLoadedMutex.WaitOne())
            {
                Debug.WriteLine("LoadEntriesSync - got mutex");
            }
            else
            {
                Debug.WriteLine("LoadEntriesSync - failed to get mutex");
            }
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (TextReader reader = new StreamReader(new IsolatedStorageFileStream("e.dat", System.IO.FileMode.Open, store), new CustomEncoding(), true))
                {
                    int cnt = 0;
                    while (true)
                    {

                        string content = reader.ReadLine();
                        if (content == null)
                            break;
                        string normalizedContent = reader.ReadLine();


                        Entry newEntry = new Entry()
                        {
                            Name = Names[cnt],
                            Content = content,
                            NormalizedContent = normalizedContent,
                            RelatedEntryNames = new List<string>()
                        };
                        string relatedEntryCountString = reader.ReadLine();
                        int relatedEntryCount = Convert.ToInt32(relatedEntryCountString);
                        for (int i = 0; i < relatedEntryCount; i++)
                        {
                            newEntry.RelatedEntryNames.Add(reader.ReadLine());
                        }
                        Entries.Add(Names[cnt], newEntry);
                        cnt++;
                    }
                }
            }
            _entryLoadedMutex.ReleaseMutex();
            Debug.WriteLine("LoadEntriesSync - releasing mutex");
        }
        private void LoadEntries_DoWork(object sender, DoWorkEventArgs e)
        {
            LoadEntriesSync();
        }

        private void LoadEntries_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.WriteLine("Entries loaded");
            _entriesLoaded = true;
        }
        private void LoadEntriesAsync()
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = false;
            bw.DoWork += new DoWorkEventHandler(LoadEntries_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LoadEntries_RunWorkerCompleted);

            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }
         
        private void SearchThread_DoWork(object sender, DoWorkEventArgs e)
        {
            PerformSearchSync(e.Argument as DictEntry);
        }

        private void SearchThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            foreach (Entry entry in ExactResults)
            {
                if(entry.Content != "")
                    if (!FinalResults.Contains(entry))
                        FinalResults.Add(entry);
                foreach (string relatedEntryName in entry.RelatedEntryNames)
                {
                    Entry relatedEntry = Entries[relatedEntryName];
                    if (!FinalResults.Contains(relatedEntry))
                        FinalResults.Add(relatedEntry);
                }
            }
            foreach (Entry entry in ProbableResults)
            {
                if(entry.Content != "")
                    if (!FinalResults.Contains(entry))
                        FinalResults.Add(entry);
                foreach (string relatedEntryName in entry.RelatedEntryNames)
                {
                    Entry relatedEntry = Entries[relatedEntryName];
                    if (!FinalResults.Contains(relatedEntry))
                        FinalResults.Add(relatedEntry);
                }             
            }

            if(FinalResults.Count == 0)
            {
                SearchHint.Visibility = Visibility.Visible;
                SearchHint.Text = AppResources.QueryNotFoundText+ ": "+CurrentQuery;
                CurrentlySelectedEntry = null;
            }
            else
            {
                SearchHint.Visibility = Visibility.Collapsed;
                SearchsListSelector.Focus();
                ShowAd();
            }
            searchInProgres = false;
            _entryLoadedMutex.ReleaseMutex();
            Debug.WriteLine("SearchThread_RunWorkerCompleted - released mutex");
            
        }

        private void PerformSearchAsync(DictEntry query)
        {

            if (_entryLoadedMutex.WaitOne())
            {
                Debug.WriteLine("PerformSearchSync - got mutex");
            }
            else
            {
                Debug.WriteLine("PerformSearchSync - failed to get mutex");
            }
            searchInProgres = true;
            CurrentQuery = query;
            //query = StringUtil.RemoveDiacritics(query);
            //query.TrimEnd(' ');
            ProbableResults.Clear();
            ExactResults.Clear();
            FinalResults.Clear();



            if (query.Id != QUERY_ID_UNDEFINED)
            {
                Entry resolvedEntry = Entries[query.Name];
                ExactResults.Add(resolvedEntry);
                SearchThread_RunWorkerCompleted(null,null);
                return;
            }

            SearchHint.Visibility = Visibility.Visible;
            SearchHint.Text = AppResources.SearchInProgressText;
            //customEntry.normalizedName = query;
            //if(!isHistorySearch)
            //    History.Save(customEntry);

            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = false;
            bw.WorkerReportsProgress = false;
            bw.DoWork += new DoWorkEventHandler(SearchThread_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(SearchThread_RunWorkerCompleted);

            //ResultPanel.Children.Clear();
            //HtmlBox resultBox = new HtmlBox();
            //resultBox.HtmlText = "Wyszukiwanie...";
            //ResultPanel.Children.Add(resultBox);
            //InProgressBox.Text = "Wyszukiwanie...";
            //InProgressBox.Visibility = System.Windows.Visibility.Visible;

            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync(query);
            }
        }

        private void PerformSearchSync(DictEntry query)
        {
            int resultsCount = 0;
            int distance;

            if (Suggestions[query.NormalizedName[0]] == null)
                return;

            foreach (DictEntry entry in Suggestions[query.NormalizedName[0]])
            {    
                distance = LevenshteinDistance.Compute(query.Name, entry.NormalizedName);
                if (distance == 0)
                {
                    ExactResults.Add(Entries.Values.ToList()[entry.Id]);
                    resultsCount++;
                }
                else if (distance < MAX_LEVENSHTEIN_DISTANCE)
                {
                    ProbableResults.Add(Entries.Values.ToList()[entry.Id]);
                }

                if (resultsCount >= MAX_SEACH_RESULTS)
                {
                    break;
                }
            }
            if(ExactResults.Count == 0)//search in content
            {
                foreach (Entry entry in Entries.Values)
                {
                    if (resultsCount >= MAX_SEACH_RESULTS)
                    {
                        break;
                    }
                    if (Regex.IsMatch(entry.NormalizedContent, "\\b" + query + "\\b"))
                    {
                        if (!ExactResults.Contains(entry))
                        {
                            ExactResults.Add(entry);
                            resultsCount++;
                        }
                    }
                }
            }   
            //}
            
        }


        

        private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
        {
            UpdateDatabaseAsync();
        }

        private void ApplicationBarMenuItem_Click_1(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/AboutPage.xaml", UriKind.Relative));

        }

        private void onSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            pageSelected = rootPivot.SelectedIndex;
            System.Diagnostics.Debug.WriteLine(pageSelected);
            if (pageSelected == 0)
            {
                queryInput.AnimateShowInput();
                if(!isUpdatingDatabase)
                    queryInput.Input.Focus();
            }
            else
            {

                queryInput.AnimateHideInput();
                FavouritesListSelector.Focus();
                if (FavouritesListSelector.ItemsSource == null)
                {
                    FavouritesListSelector.ItemsSource = EntryStorage.Instance.GetFavs();
                }
            }
        }


        private void ExpanderOnTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            Debug.WriteLine("Expander tapped");
        }

        private void ExpanderOnHold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            Debug.WriteLine("Expander holded");
        }

        private void DeleteButtonClick(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Delete entry tapped");
            Button ctrl = sender as Button;
            FavouriteItem fav = ctrl.DataContext as FavouriteItem;
            EntryStorage.Instance.DeleteFavourite(fav);
            foreach(Entry displayedEntry in FinalResults)//check if fav to delete is not currently displayed n the search section. If so, update
            {
                if(displayedEntry.Name == fav.Name)
                {
                    displayedEntry.IsInFavourites = false;
                }
            }
            //entry.IsInFavourites = false;
            //Debug.WriteLine("Deleting " + entry.name);
            //Favourites.Delete(entry);
        }

        private void AddFavouriteButtonClick(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Add to favourite tapped");
            Button ctrl = sender as Button;
            Entry entry = ctrl.DataContext as Entry;
            entry.IsInFavourites = true;
            Debug.WriteLine("Adding " + entry.Name);
            EntryStorage.Instance.StoreFavourite(entry);
            //Favourites.Save(entry);
            //FavouritesList list = (FavouritesList)FavouritesListSelector.ItemsSource;
        }

        private void ClearRoot()
        {
            Debug.WriteLine("Clearing Root");
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                String[] dirNames = store.GetDirectoryNames("*");
                String[] fileNames = store.GetFileNames("*");

                if (fileNames.Length > 0)
                {
                    for (int i = 0; i < fileNames.Length; ++i)
                    {
                        // Delete the files.
                        store.DeleteFile(fileNames[i]);
                    }
                }
            }
        }

        private void CheckIfAddFree()
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (store.FileExists(NOADS_FILENAME))
                {
                    _isAdFreeVersion = true;
                    if ((ApplicationBar as ApplicationBar).MenuItems.Count == 3)
                    {
                        (ApplicationBar as ApplicationBar).MenuItems.RemoveAt(1);//delete remove ads button if it exists
                    }
                }
            }
                
            
            
        }
        private void ShowAd()
        {
            if (!_isAdFreeVersion)
                AdWindow.Visibility = Visibility.Visible;  
        }
        private void CloseAd()
        {
            AdWindow.Visibility = Visibility.Collapsed;
        }
        private void CloseAdButtonClick(object sender, System.Windows.Input.GestureEventArgs e)
        {
            CloseAd();
        }

        /*private void AdReadyEvent(object sender, Microsoft.AdMediator.Core.Events.AdSdkEventArgs e)
        {
            Debug.WriteLine("AdFilled: " + e.Name);
        }*/

        async private void ApplicationBarMenuItem_RemoveAds(object sender, EventArgs e)
        {
            try
            {
                var listing = await CurrentApp.LoadListingInformationAsync();
                var obj = listing.ProductListings.FirstOrDefault(
                           p => p.Value.ProductId == NOADS_PRODUCT_ID);
                if (CurrentApp.LicenseInformation.ProductLicenses[obj.Value.ProductId].IsActive)
                {
                    MessageBox.Show("You already own an ad free version!");
                }
                else
                {

                    receipt = await CurrentApp.RequestProductPurchaseAsync(obj.Value.ProductId, true);
                    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        store.CreateFile(NOADS_FILENAME).Close();
                    }
                    (ApplicationBar as ApplicationBar).MenuItems.RemoveAt(1);
                    AdWindow.Visibility = Visibility.Collapsed;
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.ToString());
            }          


        }

    }
}